package brs.http;

import brs.*;
import brs.services.AccountService;
import brs.services.ParameterService;
import brs.util.Convert;
import com.google.gson.JsonElement;

import javax.servlet.http.HttpServletRequest;

import java.math.BigDecimal;

import static brs.http.JSONResponses.NOT_ENOUGH_ASSETS;
import static brs.http.JSONResponses.NOT_ENOUGH_FUNDS;
import static brs.http.JSONResponses.SAME_ASSET;
import static brs.http.common.Parameters.*;
import static brs.http.common.ResultFields.UNSIGNED_TRANSACTION_BYTES_RESPONSE;

final class PlaceBidOrder extends CreateTransaction {

  private final ParameterService parameterService;
  private final Blockchain blockchain;
  private final AccountService accountService;

  PlaceBidOrder(ParameterService parameterService, Blockchain blockchain, APITransactionManager apiTransactionManager,AccountService accountService) {
    super(new APITag[] {APITag.AE, APITag.CREATE_TRANSACTION}, apiTransactionManager, ASSET_PARAMETER, QUANTITY_QNT_PARAMETER, PRICE_NQT_PARAMETER);
    this.parameterService = parameterService;
    this.blockchain = blockchain;
    this.accountService = accountService;
  }

  //把数字转换成最小单位
  private long toNQT(String amount, byte decimals) {
    long exp = (long) Math.pow(10, decimals);

    return new BigDecimal(amount).multiply(new BigDecimal(String.valueOf(exp))).longValue();
  }

  @Override
  JsonElement processRequest(HttpServletRequest req) throws BurstException {

    Asset asset = parameterService.getAsset(req);
    String assetValue = Convert.emptyToNull(req.getParameter(QUOTE_ASSET_ID_PARAMETER));
    long quoteAssetId = 0l;
    byte quoteAssetDecimals = 8;
    if (!assetValue.equals("0")) {
      Asset quoteAsset = parameterService.getQuoteAsset(req);
      quoteAssetId = quoteAsset.getId();
      quoteAssetDecimals = quoteAsset.getDecimals();
    }

    if (asset.getId() == quoteAssetId) {
      return SAME_ASSET;
    }

    //价格NQT = 原始价格 * math.pow(10, 定价资产的decimals)
    long priceNQT = toNQT(Convert.emptyToNull(req.getParameter(PRICE_NQT_PARAMETER)), quoteAssetDecimals);
    //数量NQT = 原始数量 * math.pow(10,基本资产的decimals)
    long quantityQNT = toNQT(Convert.emptyToNull(req.getParameter(QUANTITY_QNT_PARAMETER)), asset.getDecimals());
    //总金额 = 原始数量 * priceNQT
    long totalAmountNQT = new BigDecimal(Convert.emptyToNull(req.getParameter(QUANTITY_QNT_PARAMETER))).multiply(new BigDecimal(priceNQT)).longValue();

    long feeNQT = ParameterParser.getFeeNQT(req);
    Account account = parameterService.getSenderAccount(req);

    if (quoteAssetId == 0) {
      try {
        if (Convert.safeAdd(feeNQT, totalAmountNQT) > account.getUnconfirmedBalanceNQT()) {
          return NOT_ENOUGH_FUNDS;
        }
      } catch (ArithmeticException e) {
        return NOT_ENOUGH_FUNDS;
      }
    } else {
      try {
        if (feeNQT > account.getUnconfirmedBalanceNQT()) {
          return NOT_ENOUGH_FUNDS;
        }

        long quoteAssetBalance = accountService.getUnconfirmedAssetBalanceQNT(account, quoteAssetId);
        if (quoteAssetBalance < 0 || totalAmountNQT > quoteAssetBalance) {
          return NOT_ENOUGH_ASSETS;
        }
      } catch (ArithmeticException e) {
        return NOT_ENOUGH_FUNDS;
      }
    }


    Attachment attachment = new Attachment.ColoredCoinsBidOrderPlacement(asset.getId(), quantityQNT, priceNQT, quoteAssetId, blockchain.getHeight(),  (int)(System.currentTimeMillis()/ 1000l));
    JsonElement transaction1 = createTransaction(req, account, attachment);
    String transactionBytes = transaction1.getAsJsonObject().get(UNSIGNED_TRANSACTION_BYTES_RESPONSE).getAsString();

    Transaction transaction = parameterService.parseTransaction(transactionBytes, null);

    return transaction1;

  }

}
